﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Timers;

namespace Pacol
{
    class Enemy
    {
        private double[] _position;
        private Block _targetBlock;
        private Color _color;
        private Labyrinth _labyrinth;
        private List<Block> _respawnArea;
        private Block _respawnBlock;
        private double _elapsedTime;
        private Texture2D _texture;
        private Rectangle _rect;
        private Rectangle[] _texSource;
        private int _direction;
        public static double _speedParam = 0.00015;
        private Random _rand;
        private bool _stuck;
        private int _pose;
        public bool _pop;
        public int _animPop = 0;
        private Timer timerAnimPop = new Timer(600);
        public static bool _accelerated = false;

        public Enemy(Color color, Labyrinth labyrinth, List<Block> respawnArea, Texture2D texture)
        {
            _color = color;
            _labyrinth = labyrinth;
            _respawnArea = respawnArea;
            _texture = texture;
            _texSource = new Rectangle[2];
            _texSource[0] = new Rectangle(0, 0, 128, 128);
            _texSource[1] = new Rectangle(128, 0, 128, 128);
            _pose = 0;
            _position = new double[2];
            _rand = new Random();
            _stuck = true;
            _pop = true;
            timerAnimPop.Elapsed += timerAnimPop_Elapsed;
            timerAnimPop.Start();
        }

        void timerAnimPop_Elapsed(object sender, ElapsedEventArgs e)
        {
            _animPop += 1;

            if (_animPop >= 3)
            {
                timerAnimPop.Stop();
                _pop = false;
                _animPop = 0;
            }
        }

        public void Respawn(double[] posPlayer)
        {
            _pop = true;

            do
            {
                _respawnBlock = _respawnArea[_rand.Next(_respawnArea.Count)];
            } while (_labyrinth.GetBlockAt((int)posPlayer[0], (int)posPlayer[1]) == _respawnBlock);

            timerAnimPop.Start();

            _position[0] = _respawnBlock.x;
            _position[1] = _respawnBlock.y;
            _targetBlock = _respawnBlock;
            _rect = new Rectangle((int)_position[0], (int)_position[1], _labyrinth.blockSize, _labyrinth.blockSize);
        }

        public void Update(GameTime gameTime, Color playerColor)
        {
            double tmpTargetX;
            double tmpTargetY;
            Block tmpBlock;

            if (!_pop)
            {
                _elapsedTime = gameTime.ElapsedGameTime.TotalMilliseconds;

                if (_targetBlock.x == _position[0] && _targetBlock.y == _position[1])
                {
                    _stuck = true;

                    // the enemy want to move upwardly
                    if (_direction == 0)
                    {
                        tmpBlock = _labyrinth.GetBlockAt((int)_position[0], (int)_position[1]);

                        if (tmpBlock.colorTop.Equals(_color))
                        {
                            tmpTargetY = tmpBlock.y - _labyrinth.blockSize;

                            if (tmpTargetY >= 0)
                            {
                                _stuck = false;
                                _targetBlock = _labyrinth.GetBlockAt((int)_position[0], (int)tmpTargetY);
                                Move(gameTime);
                            }
                        }
                    }
                    // the enemy want to move to the right
                    else if (_direction == 1)
                    {
                        tmpBlock = _labyrinth.GetBlockAt((int)_position[0], (int)_position[1]);

                        if (tmpBlock.colorRight.Equals(_color))
                        {
                            tmpTargetX = tmpBlock.x + _labyrinth.blockSize;

                            if (tmpTargetX < _labyrinth.width * _labyrinth.blockSize)
                            {
                                _stuck = false;
                                _targetBlock = _labyrinth.GetBlockAt((int)tmpTargetX, (int)_position[1]);
                                Move(gameTime);
                            }
                        }
                    }
                    // the enemy want to move downwardly
                    else if (_direction == 2)
                    {
                        tmpBlock = _labyrinth.GetBlockAt((int)_position[0], (int)_position[1]);

                        if (tmpBlock.colorBottom.Equals(_color))
                        {
                            tmpTargetY = tmpBlock.y + _labyrinth.blockSize;

                            if (tmpTargetY < _labyrinth.height * _labyrinth.blockSize)
                            {
                                _stuck = false;
                                _targetBlock = _labyrinth.GetBlockAt((int)_position[0], (int)tmpTargetY);
                                Move(gameTime);
                            }
                        }
                    }
                    // the enemy want to move to the left
                    else if (_direction == 3)
                    {
                        tmpBlock = _labyrinth.GetBlockAt((int)_position[0], (int)_position[1]);

                        if (tmpBlock.colorLeft.Equals(_color))
                        {
                            tmpTargetX = tmpBlock.x - _labyrinth.blockSize;

                            if (tmpTargetX >= 0)
                            {
                                _stuck = false;
                                _targetBlock = _labyrinth.GetBlockAt((int)tmpTargetX, (int)_position[1]);
                                Move(gameTime);
                            }
                        }
                    }

                    if (_stuck)
                        _direction = _rand.Next(4);
                }
                else
                {
                    _stuck = false;
                    Move(gameTime);
                }
            }
        }

        public void Move(GameTime gameTime)
        {
            // the enemy moves upwardly
            if (_direction == 0)
            {
                _position[1] -= _elapsedTime * speed;

                if (_position[1] < _targetBlock.y)
                    _position[1] = _targetBlock.y;
            }
            // the enemy moves to the right
            else if (_direction == 1)
            {
                _pose = 0;
                _position[0] += _elapsedTime * speed;

                if (_position[0] > _targetBlock.x)
                    _position[0] = _targetBlock.x;
            }
            // the enemy moves downwardly
            else if (_direction == 2)
            {
                _position[1] += _elapsedTime * speed;

                if (_position[1] > _targetBlock.y)
                    _position[1] = _targetBlock.y;
            }
            // the enemy moves to the left
            else if (_direction == 3)
            {
                _pose = 1;
                _position[0] -= _elapsedTime * speed;

                if (_position[0] < _targetBlock.x)
                    _position[0] = _targetBlock.x;
            }

            _rect.X = (int)_position[0];
            _rect.Y = (int)_position[1];
        }

        public void Draw(SpriteBatch spriteBatch, GameTime gameTime)
        {
            if (!_pop)
                spriteBatch.Draw(_texture, _rect, _texSource[_pose], Color.White);
            else 
                spriteBatch.Draw(Game1._flashTex, new Rectangle((int)this._position[Game1.x], (int)this._position[Game1.y], (int)this._labyrinth.blockSize, (int)this._labyrinth.blockSize), new Rectangle(0, _animPop * 25, 25, 25), Color.White);
        }

        public Rectangle rect
        {
            get { return _rect; }
        }

        public Color color
        {
            get { return _color; }
            set { _color = value; }
        }

        public Texture2D texture
        {
            set { _texture = value; }
        }

        public double speed
        {
            get { return _labyrinth.blockSize * _speedParam; }
        }
    }
}
